/*******************************************************************************
 * Copyright (c) 2009 asEclipse
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.aseclipse.osgi
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.utils.Dictionary;
    
    import mx.core.IContainer;
    import mx.logging.ILogger;
    import mx.logging.Log;
    
    import org.aseclipse.core.runtime.app.AppManager;
    import org.aseclipse.osgi.classes.BundleFrameworkImpl;
    import org.aseclipse.osgi.loader.BundleConstants;

/**
 * The god of Flex OSGi World.
 * 
 */    
public class BundleEngine extends EventDispatcher
{
    public static const LOAD_CONFIG_READY:String = "ConfigReadyEvent";
    public static const LOAD_CONFIG_FAIL:String = "ConfigFailEvent";
    public static const STARTUP_BUNDLE_SEP1:String = ",";
    public static const STARTUP_BUNDLE_SEP2:String = "@";
    public static const STATUS_INITIAL:String = "initial";
    public static const STATUS_STARTED:String = "started";
    public static const STATUS_STOPED:String = "stoped";
    
    private static var log_:ILogger =  Log.getLogger("BundleEngine");
    // multiple bundle instances support
    private static var instances:Dictionary = new Dictionary();
    
    // control the app management
    private static var appMgr:AppManager = new AppManager(); 
    
    // belong to one bundle instance
    private var framework_:BundleFrameworkImpl;
    private var domain_:String;
    private var status_:String;
    private var parent_:IContainer; // the container to hold current Bundle framework
    
    public function BundleEngine(domain:String) {
        if(instances[domain] != null) {
            throw new Error("'" + domain+ "' BundleEngine already exists, can't initialize twice");
        }
        domain_ = domain;
        framework_ = new BundleFrameworkImpl();
        status_ = STATUS_INITIAL;
    }
    
    /********
    * OSGiEngine has multiple instances separated by domain.
    * For single usage, just use OSGiEngine.getInstance() to get default instance.
    * 
    */ 
    public static function getInstance(domain:String = "default"):BundleEngine {
        if(instances[domain] == null) {
            var engine:BundleEngine = new BundleEngine(domain);
            instances[domain] = engine;
        }
        return instances[domain];
    }
    
    public static function getAppManager():AppManager {
        return appMgr;
    }
    
    public function getBundleFramework():BundleFramework {
        return framework_;
    }
    
    public function getContainer():IContainer {
        return parent_;
    }
    /*******
    * Auto start OSGi framework
    * 1) load config.ini from current swf's root location;
    * 2) get "osgi.bundles" value and start these bundles one by one.
    * 3) after loading and starting all bundles, FrameworkEvent.FRAMEWORK_EVENT with 
    *     STARTED state will be dispatched at BundleFramework.
    */ 
    public function autostart(parent:IContainer = null):void {
        parent_ = parent;
        if(framework_.isStarted(BundleConstants.STARTUP_BUNDLE)) {
            appMgr.autoStart(parent);
        } else {
            framework_.getBundleDispatcher().addEventListener(BundleEvent.BUNDLECHANGED, function(event:BundleEvent):void {
                if(event.getState() == BundleEvent.STARTED && 
                    event.getBundle().getSymbolicName() == BundleConstants.STARTUP_BUNDLE)
                    appMgr.autoStart(parent);
            });
            framework_.startBundle(BundleConstants.STARTUP_BUNDLE);
        }        
        status_ = STATUS_STARTED;
    }
    
    /*************
    * Start application in parent container
    * 
    */ 
    public function startApplication( appId:String, parent:IContainer = null):void {
        parent_ = parent;
        if(framework_.isStarted(BundleConstants.STARTUP_BUNDLE)) {
            appMgr.startApp(appId, parent);
        } else {
            framework_.getBundleDispatcher().addEventListener(BundleEvent.BUNDLECHANGED, function(event:BundleEvent):void {
                if(event.getState() == BundleEvent.STARTED && 
                    event.getBundle().getSymbolicName() == BundleConstants.STARTUP_BUNDLE)
                    appMgr.startApp(appId, parent);
            });
        }
        status_ = STATUS_STARTED;
    }
        
    public function shutdown():void {
        framework_.shutdown();
        status_ = STATUS_STOPED;
    }
}
}
